package helloworld.rmi;

import java.io.Serializable;

import desktop.conf.PlayFieldConf;
import desktop.core.square.ComparableSquare;

@SuppressWarnings("serial")
public class PlayFieldModel implements Serializable {
	/** bar的columnId从0到column-1 **/
	private final int column;
	private final int row;
	private final int length;

	private ComparableSquare[][] squares;

	/** 全局变量，小心操作 **/
	private boolean[][] eiminatables;
	private int pointsTotal = 0;
	private int pointsByOneElimination;

	public PlayFieldModel() {
		this(PlayFieldConf.getColumn(), PlayFieldConf.getRow(), PlayFieldConf
				.getLength());
	}

	public PlayFieldModel(int column, int row, int length) {
		this.column = column;
		this.row = row;
		this.squares = new ComparableSquare[this.column][this.row];
		this.length = length;
	}

	public int getColumn() {
		return column;
	}

	public int getRow() {
		return row;
	}

	public int getLength() {
		return length;
	}

	public ComparableSquare getSquare(int columnId, int rowId) {
		return this.squares[columnId][rowId];
	}

	public void setSquare(int columnId, int rowId, ComparableSquare square) {
		this.squares[columnId][rowId] = square;
	}

	public boolean isEiminatable(int columnId, int rowId) {
		return this.eiminatables[columnId][rowId];
	}

	public int getPointsTotal() {
		return pointsTotal;
	}

	public int getPointsByOneElimination() {
		return pointsByOneElimination;
	}

	/**
	 * squares[columnId][返回值-1] == null， squares[columnId][返回值] != null。
	 */
	public int getCurrentBottomRowId(int columnId) {
		int currentBottomRowId = this.row - 1;
		while (this.squares[columnId][currentBottomRowId] != null) {
			currentBottomRowId--;
		}
		return currentBottomRowId + 1;
	}

	public boolean eliminationExists() {
		this.eiminatables = new boolean[this.column][this.row];
		this.pointsByOneElimination = 0;

		for (int i = 0; i < this.column; i++) {
			for (int j = 0; j < this.row; j++) {
				int pointsToGain = this.checkSquare(i, j);
				this.pointsByOneElimination += pointsToGain;
				this.pointsTotal += pointsToGain;
			}
		}
		for (int i = 0; i < this.column; i++) {
			for (int j = 0; j < this.row; j++) {
				if (this.eiminatables[i][j]) {
					return true;
				}
			}
		}
		return false;
	}

	public void eliminateSimply() {
		for (int i = 0; i < this.column; i++) {
			for (int j = 0; j < this.row; j++) {
				if (this.eiminatables[i][j]) {
					this.squares[i][j] = null;
				}
			}
		}
	}

	public void applyGravity() {
		for (int i = 0; i < this.column; i++) {
			ComparableSquare[] tmpSquares = new ComparableSquare[this.row];
			int index = this.row - 1;
			for (int j = this.row - 1; j >= 0; j--) {
				if (this.squares[i][j] != null) {
					tmpSquares[index--] = this.squares[i][j];
				}
			}
			for (int j = 0; j < this.row; j++) {
				this.squares[i][j] = tmpSquares[j];
			}
		}
	}

	/**
	 * 标记全局变量eiminatables[][]，并根据points计算规则，返回获得的points数目
	 * 对于每个square，检查四个长度为length的square组（水平，垂直，右上，右下）,所以返回值只可能为0,1,2,3,4
	 */
	private int checkSquare(int columnId, int rowId) {
		int pointsToGain = 0;
		// 水平方向
		pointsToGain += this.checkSquareOnDirection(columnId, rowId, 1, 0);
		// 竖直方向
		pointsToGain += this.checkSquareOnDirection(columnId, rowId, 0, 1);
		// 右下方向
		pointsToGain += this.checkSquareOnDirection(columnId, rowId, 1, 1);
		// 右上方向
		pointsToGain += this.checkSquareOnDirection(columnId, rowId, 1, -1);
		return pointsToGain;
	}

	/**
	 * @param h
	 *            水平方向向量,1 -1 或 0
	 * @param v
	 *            垂直方向向量,1 -1 或 0
	 * @return 1 代表该检测列是可削去的，0 则相反
	 */
	private int checkSquareOnDirection(int columnId, int rowId, int h, int v) {
		boolean eiminatable = true;
		ComparableSquare[] squareList = new ComparableSquare[length];
		for (int i = 0; i < length; i++) {
			if ((columnId + h * i < 0) || (columnId + h * i >= this.column)
					|| (rowId + v * i < 0) || (rowId + v * i >= this.row)) {
				return 0;
			}
			if (this.squares[columnId + h * i][rowId + v * i] == null) {
				return 0;
			}
			squareList[i] = this.squares[columnId + h * i][rowId + v * i];
		}
		for (int i = 0; i < length - 1; i++) {
			eiminatable = eiminatable
					&& (squareList[i].sameTypeAs(squareList[i + 1]));
		}
		if (eiminatable) {
			for (int i = 0; i < length; i++) {
				this.eiminatables[columnId + h * i][rowId + v * i] = true;
			}
			return 1;
		} else {
			return 0;
		}
	}

	/** debug用 **/
	public void display() {
		for (int i = 0; i < this.row; i++) {
			for (int j = 0; j < this.column; j++) {
				if (this.squares[j][i] != null) {
					System.out.print(this.squares[j][i].typeAsInt());
				} else {
					System.out.print("x");
				}
			}
			System.out.println();
		}
		System.out.println("---------");
	}
}